#include <stdlib.h>
#include <stdio.h>
#include "fonctions.h"
#include <time.h>
#include <sys/time.h> //permet de mesurer le temps passe dans les fonctions
#include <string.h>



//calcul le tps pris entre 2 lecture de gettimeofday()
inline double deltaT(struct timeval debT, struct timeval finT)
{
	return finT.tv_sec - debT.tv_sec + (finT.tv_usec - debT.tv_usec)/1.E6;
}


/****************Produit matrice_dense 2D************************************/
//fonction produit matrice dense 2D
void GEMV_2D(T **A,T *u,T *v, int dim1, int dim2, int f_compteur)
{
	//parametres chronometre
	struct timeval debT, finT;
	int compteur=0;
	double temps_moy=0.0; //temps moyen
 
	//declaration parametres
	int i,k;
	
	//initialisation de v a 0
	for (i=0;i<dim1;i++)
	{v[i]=(T)0;}

	while(compteur<f_compteur)
	{
		//top chrono
		gettimeofday(&debT,NULL);	
		//calcul produit
		for(i=0;i<dim1;i++)
		{
			for (k=0;k<dim2;k++)
			{
				v[i]=v[i]+A[i][k]*u[k];
			}
			 //printf("v[%d]=%f\n",i,v[i]); //on affiche le vecteur resultat
		}
		//stop chrono
		gettimeofday(&finT,NULL);
		temps_moy=temps_moy+deltaT(debT,finT);
		compteur++;
	}

	temps_moy = temps_moy/((double)f_compteur);
	printf("%.16f",temps_moy);

}
/************************************************************************/

/****************Produit matrice_dense 1D************************************/
//fonction produit matrice dense 1D
void GEMV_1D(T *A,T *u,T *v, int dim1, int dim2, int f_compteur)
{
	//parametres chronometre
	struct timeval debT, finT;
	int compteur=0;
	double temps_moy=0.0; //temps moyen
 
	//declaration parametres
	int i,k;
	
	//initialisation de v a 0
	for (i=0;i<dim1;i++)
	{v[i]=(T)0;}

	while(compteur<f_compteur)
	{
		//top chrono
		gettimeofday(&debT,NULL);	
		//calcul produit
		for(i=0;i<dim1;i++)
		{
			for (k=0;k<dim2;k++)
			{
				v[i]=v[i]+A[i+dim1*k]*u[k];
			}
			// printf("v[%d]=%d\n",i,v[i]); //on affiche le vecteur resultat
		}
		//stop chrono
		gettimeofday(&finT,NULL);
		temps_moy=temps_moy+deltaT(debT,finT);
		compteur++;
	}

	temps_moy = temps_moy/((double)f_compteur);
	printf("%.16f",temps_moy);

}
/************************************************************************/

/*****************Produit avec stockage COOrdinate**********************************/
//fonction matrice creuse COO
 void SPMV_COO(int **Indice,T *Values,T *u,T *v,int dim, int f_compteur)
{
	//forme matrice creuse
	char forme[]= "stockage COOrdinate";
	
	//parametres chronometre
	int compteur=0;
	double temps_moy=0.0; //temps moyen
	struct timeval debT, finT;
	  
	//declaration parametres
	int i;
	for(i=0;i<dim;i++)
	{ v[i]=0;}//initialisation de v a 0
		
	while(compteur<f_compteur)
	{
		// debut chrono
		gettimeofday(&debT,NULL);
		//calcul produit
		for(i=0;i<dim;i++)
		{
			v[Indice[i][0]]=v[Indice[i][0]]+Values[i]*u[Indice[i][1]];
			// printf("v[%d]=%d\n",i,v[i]);
		}
		//fin chronometre
		gettimeofday(&finT,NULL);
		temps_moy=temps_moy+deltaT(debT,finT);
		compteur++;
	}

	temps_moy = temps_moy/((double)f_compteur);
	printf("%.16f",temps_moy);
}
/************************************************************************/

/***************Produit avec stockage Compressed Storage Row**********************************/
//fonction matrice creuse CSR
void SPMV_CSR(int *IA, int *JA, T *Values, T *u, T *v, int dim, int f_compteur)
{
	//forme matrice creuse
	char forme[]= "stockage Compressed Storage Row";
	
	 //parametres chronometre
	int compteur=0;
	double temps_moy=0.0; //temps moyen
	struct timeval debT, finT;
  
	//declaration parametres
	int i,k,j,l;

	while(compteur<f_compteur)
	{
		for(i=0;i<dim;i++)
		{ v[i]=0;}//initialisation de v a 0
		// debut chrono
		gettimeofday(&debT,NULL);
		//calcul produit
		for(i=0;i<dim;i++)
		{
			for(k=IA[i];k<IA[i+1];k++)
			{
				v[i]=v[i]+Values[k]*u[JA[k]];
				// printf("v[%d]=%d\n",i,v[i]);
			}
		}
		//fin chronometre
		gettimeofday(&finT,NULL);
		temps_moy=temps_moy+deltaT(debT,finT);
		compteur++;
	}

	temps_moy = temps_moy/((double)f_compteur);
	printf("%.16f",temps_moy);
}
/*****************************************************************************/


/***************Produit avec stockage Ellpack_Itpack*******************************/

void SPMV_EI(T **AA,int **JA,T *u, T *v,int dim,int Nmax, int f_compteur)
{
	//forme matrice creuse
	char forme[]= "stockage Ellpack Itpack";
	
	//parametres chronometre
	int compteur=0;
	double temps_moy=0.0; //temps moyen
	struct timeval debT, finT;
	
	//declaration parametres
	int i,k;
	
	for(i=0;i<dim;i++)
		{ v[i]=0;}//initialisation de v a 0
	
		
	while(compteur<f_compteur)
	{
		// debut chrono
		gettimeofday(&debT,NULL);
		//calcul produit
		for(i=0;i<dim;i++)
		{
			for(k=1;k<Nmax;k++)
			{
				v[i]=v[i]+AA[i][k]*u[JA[i][k]];
				// printf("v[%d]=%d\n",i,v[i]);
			}
		}
		//fin chronometre
		gettimeofday(&finT,NULL);
		temps_moy=temps_moy+deltaT(debT,finT);
		compteur++;
	}

	temps_moy = temps_moy/((double)f_compteur);
	printf("%.16f",temps_moy);
}

/**********************Produit avec stockage BaNDe*****************************************/
void SPMV_BND(T **Bande,T *u, T *v,int dim,int nbBandeInf,int nbBandeSup, int f_compteur)
{
	//forme matrice creuse
	char forme[]= "stockage BaNDe";
	
	//parametres chronometre
	int compteur=0;
	double temps_moy=0.0; //temps moyen
	struct timeval debT, finT;
	
	int max, min;
  
	//declaration parametres
	int i,k;
    for(i=0;i<dim;i++)
	{ v[i]=0;}//initialisation de v a 0
	
	while(compteur<f_compteur)
	{
	
		// debut chrono
		gettimeofday(&debT,NULL);

		//calcul produit
		for(i=0;i<dim;i++)
		{
			for(k=0;k<nbBandeInf+nbBandeSup+1;k++)
			{
				max= k>k+i-nbBandeInf ? k : k+i-nbBandeInf;
				min=dim < max ? dim : max;
				v[i]=v[i]+Bande[i][k]*u[min];
			}
		}
		//fin chronometre
		gettimeofday(&finT,NULL);
		temps_moy=temps_moy+deltaT(debT,finT);
		compteur++;
	}

	temps_moy = temps_moy/((double)f_compteur);
	printf("%.16f",temps_moy);
}
